import { useState, useEffect, useCallback, useRef } from 'react'

// 定义请求状态类型
export type FetchStatus = 'idle' | 'loading' | 'success' | 'error'

// 定义配置选项接口
export interface UseFetchOptions<T> {
  // 初始数据
  initialData?: T
  // 是否自动执行
  autoFetch?: boolean
  // 重试次数
  retryCount?: number
  // 重试延迟(ms)
  retryDelay?: number
  // 缓存时间(ms)
  cacheTime?: number
  // 成功回调
  onSuccess?: (data: T) => void
  // 错误回调
  onError?: (error: Error) => void
  // 完成回调
  onFinally?: () => void
  // 请求依赖项
  dependencies?: any[]
}

// 定义返回值接口
export interface UseFetchResult<T> {
  // 数据
  data: T | undefined
  // 加载状态
  isLoading: boolean
  // 请求状态
  status: FetchStatus
  // 错误信息
  error: Error | null
  // 手动刷新
  refresh: () => Promise<void>
  // 手动执行请求
  execute: (...args: any[]) => Promise<void>
  // 取消请求
  cancel: () => void
  // 重置状态
  reset: () => void
}

export function useFetch<T>(
  callback: (...args: any[]) => Promise<T>,
  options: UseFetchOptions<T> = {},
): UseFetchResult<T> {
  const {
    initialData,
    autoFetch = true,
    retryCount = 0,
    retryDelay = 1000,
    cacheTime = 0,
    onSuccess,
    onError,
    onFinally,
    dependencies = [],
  } = options

  const [data, setData] = useState<T | undefined>(initialData)
  const [status, setStatus] = useState<FetchStatus>('idle')
  const [error, setError] = useState<Error | null>(null)

  // 使用 ref 存储一些不需要触发重渲染的值
  const retryCountRef = useRef(0)
  const abortControllerRef = useRef<AbortController | null>(null)
  const cacheRef = useRef<{
    data?: T
    timestamp: number
  }>({
    timestamp: 0,
  })

  // 清理函数
  const cleanup = useCallback(() => {
    if (abortControllerRef.current) {
      abortControllerRef.current.abort()
      abortControllerRef.current = null
    }
  }, [])

  // 重置状态
  const reset = useCallback(() => {
    setData(initialData)
    setStatus('idle')
    setError(null)
    retryCountRef.current = 0
    cleanup()
  }, [initialData, cleanup])

  // 执行请求
  const executeFetch = useCallback(
    async (...args: any[]) => {
      // 检查缓存
      if (cacheTime > 0) {
        const now = Date.now()
        if (cacheRef.current.data && now - cacheRef.current.timestamp < cacheTime) {
          setData(cacheRef.current.data)
          setStatus('success')
          return
        }
      }

      cleanup()
      setStatus('loading')
      abortControllerRef.current = new AbortController()

      try {
        const response = await callback(...args)
        setData(response)
        setStatus('success')
        setError(null)
        retryCountRef.current = 0

        // 更新缓存
        if (cacheTime > 0) {
          cacheRef.current = {
            data: response,
            timestamp: Date.now(),
          }
        }

        onSuccess?.(response)
      } catch (err) {
        // 如果是取消请求，不做处理
        if (err instanceof Error && err.name === 'AbortError') {
          return
        }

        const error = err instanceof Error ? err : new Error('Unknown error')
        setError(error)
        setStatus('error')

        // 处理重试逻辑
        if (retryCountRef.current < retryCount) {
          retryCountRef.current++
          setTimeout(() => {
            executeFetch(...args)
          }, retryDelay)
        }

        onError?.(error)
      } finally {
        onFinally?.()
      }
    },
    [
      callback,
      cacheTime,
      cleanup,
      onError,
      onFinally,
      onSuccess,
      retryCount,
      retryDelay,
    ],
  )

  // 刷新请求
  const refresh = useCallback(async () => {
    await executeFetch()
  }, [executeFetch])

  // 取消请求
  const cancel = useCallback(() => {
    cleanup()
    setStatus('idle')
  }, [cleanup])

  // 自动执行
  useEffect(() => {
    if (autoFetch) {
      executeFetch()
    }
    return cleanup
  }, [autoFetch, executeFetch, cleanup, ...dependencies])

  return {
    data,
    isLoading: status === 'loading',
    status,
    error,
    refresh,
    execute: executeFetch,
    cancel,
    reset,
  }
}

export default useFetch

/*
// 基本使用
const { data, loading, error } = useFetch(fetchData)

// 带配置的使用
const {
  data,
  loading,
  status,
  error,
  refresh,
  execute,
  cancel,
  reset
} = useFetch(fetchData, {
  initialData: [],
  autoFetch: true,
  retryCount: 3,
  retryDelay: 1000,
  cacheTime: 5000,
  onSuccess: (data) => console.log('Success:', data),
  onError: (error) => console.error('Error:', error),
  onFinally: () => console.log('Request completed'),
  dependencies: [someDepValue]
})

*/
